package com.cavy.platform.client.service;

import com.cavy.platform.client.CavyConfig;
import com.cavy.platform.client.ServerConfig;
import com.cavy.platform.client.message.Message;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.java_websocket.WebSocket;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.drafts.Draft_6455;
import org.java_websocket.handshake.ServerHandshake;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;

/**
 * @author 唐旭
 * @Date 2018/7/26
 */
@Service
@Slf4j
public class WebSocketService {
    private static final String URI_TEMPLATE = "ws://%s:%s/message/%s";
    private static final int MAX_RETRY_COUNT = 2;
    @Autowired
    private CavyConfig config;
    @Autowired
    private SystemInfoService infoService;
    @Autowired
    private List<MessageHandler> handlerList = new ArrayList<>();
    private WebSocketClient client;

    public void connectServer() {
        client.connect();
    }

    public void hand(String message) {
        ObjectMapper mapper = new ObjectMapper();
        try {
            JsonNode jsonNode = mapper.readTree(message);
            JsonNode eventName = jsonNode.get(Message.MESSAGE_TYPE_NODE_NAME);
            for (MessageHandler handler : handlerList) {
                if (handler.support(eventName.textValue())) {
                    handler.hand(message);
                }
            }
        } catch (IOException e) {
            log.error("无法读取消息,不支持的消息:{}", message);
            //此处不进行特殊处理,不支持的命令任然可以接收,但是不进行处理
            e.printStackTrace();
        }
    }

    @PostConstruct
    public void init() {
        client = new WebSocketClient(getServerWebSocketUri(), new Draft_6455()) {
            @Override
            public void onOpen(ServerHandshake serverHandshake) {
                log.debug("已连接到[{}:{}]服务器...", config.getServer().getIp(), config.getServer().getPort());
            }

            @Override
            public void onMessage(String message) {
                log.debug("收到服务器发送信息:" + message);
                hand(message);
            }

            @Override
            public void onClose(int code, String reason, boolean remote) {
                log.warn("正在断开到[{}:{}]服务器连接,参数:code:{},reason:{},remote:{}",
                        config.getServer().getIp(), config.getServer().getPort(),
                        code, reason, remote
                );
            }

            @Override
            public void onError(Exception e) {
                log.error("发生了错误,错误类型:{},错误信息:{}", e.toString(), e.getMessage());
                e.printStackTrace();
            }
        };
    }

    @PreDestroy
    public void destroy() {
        if (client != null) {
            client.close();
        }
    }

    private URI getServerWebSocketUri() {
        ServerConfig server = config.getServer();
        try {
            return new URI(String.format(URI_TEMPLATE, server.getIp(), server.getPort(), infoService.getHostName()));
        } catch (URISyntaxException e) {
            throw new RuntimeException(e);
        }
    }

    public void send(Message message) {
        message.setType(message.getClass().getSimpleName());
        while (true) {
            try {
                checkConnect();
                client.send(message.toJson());
                return;
            } catch (Exception e) {
                destroy();
                init();
                connectServer();
            }
        }
    }

    private void checkConnect() throws Exception {
        int i = 0;
        try {
            while (!client.getReadyState().equals(WebSocket.READYSTATE.OPEN) && i < MAX_RETRY_COUNT) {
                Thread.sleep(1000);
                i++;
            }
        } catch (InterruptedException e) {
            log.error(e.getMessage());
            e.printStackTrace();
            Thread.currentThread().interrupt();
        }
        if (!client.getReadyState().equals(WebSocket.READYSTATE.OPEN)) {
            log.error("无法连接到服务器,请确认服务器IP和端口");
            throw new Exception("无法连接到服务器,请确认服务器IP和端口");
        }
    }
}
